Forum Discussion
parsing a datagroup/class
Hi all,
I have this situation. Our iRule for our main website now has a lot of redirects which are based on the URI specified. There are now getting to be quite a few of these and for various reasons I won't go into it is getting to be a bit of a pain to maintain these in iRules. I briefy looked at using HTTP Classes and although they addressed some of my issues, for some reason I could not get case insensative matches to work reliably. What I am now thinking of doing is using a datagroup/class where the string name will be the URI to match on and the value will be the URI to redirect to.
eg.
StringName Value
/contactus /public/contact-us
/help /public/help
So the iRule logic would be something like
if the uri equals the value of the first element redirect to 2nd element
Obviously, it would need to repeat this until it exhausts all of the entries in the datagroup.
I feel this will be a much simpler way to manage these redirects. So, can anyone give me any pointers on how I would go about coding this in a iRule? I'm currently going over the class statement and I'll see if I can nut it out for myself, but I am not adverse to any pointers :)
tia
Craig
13 Replies
- hoolio
Cirrostratus
Hi Craig,
Here's an example which looks up the client's requested path (the /path/to/file.html in /path/to/file.html?param=value...). It does an exact match, but you could alter that by changing equals to starts_with.when HTTP_REQUEST { Check the requested path, set to lower case to see if it exists in the uri_map_dg datagroup If there is a match, save the corresponding value set new_path [class match -value -- [string tolower [HTTP::path]] equals uri_map_dg] If there was a matching path, update the requested path if {$new_path ne ""}{ HTTP::path $new_path } }
Here's an example for starts_with logic:when HTTP_REQUEST { Check the requested path, set to lower case to see if it exists in the uri_map_dg datagroup If there is a match, save the corresponding name and value to do the update set old_and_new_path [class match -element -- [string tolower [HTTP::path]] starts_with uri_map_dg] If there was a matching path, update the requested path Use string map to replace the old with the new in the path if {$new_path ne ""}{ HTTP::path [string map $old_and_new_path [HTTP::path]] } }
Aaron - CraigM_17826
Altocumulus
Hi Hollio,
Interesting how we can come up with different takes on this :) I got this to work....doesn't seem as elegant as yours though :(
set _ptr [class startsearch Friendly_URLs]
while { [class anymore Friendly_URLs $_ptr] } {
set _data [class nextelement Friendly_URLs $_ptr]
set short_uri [lindex [string tolower $_data] 0]
set redirect_uri [lindex [string tolower $_data] 1]
if { $lc_uri equals $short_uri } {
HTTP::redirect "$redirect_uri"
}
}
Still needs some validation work to ensure the datagroup contains two elements per line, but it does work, just a bit more convoluted than your solution. Actually I aquired this code from some sample code in the sample code area, so I suppose I should blame the original author! :)
Craig - Colin_Walker_12Historic F5 AccountThere are always lots of ways to do things when programming, and adding a layer of networking options to the mix doesn't narrow your choices much. ;)
That said, if you're looking for efficiency it looks like Aaron's suggestion will likely scale to greater lengths. If yours is working and that isn't a huge concern, however, then it's a moot point.
Colin - hoolio
Cirrostratus
Using class match should return the longest (most accurate) match and be more efficient than manually looping through the data group contents entry by entry and tracking which match is the longest.
Aaron - CraigM_17826
Altocumulus
Thanks for the comments everyone. I'll give Aaron's code a try and see how it goes.
Craig - CraigM_17826
Altocumulus
Hi Arron,
It works like a charm except for one small issue I am having a bit of a problem getting it to work. Just trying to get it to do a case insensative match on both the [HTTP::path] as well as the returned contents from the datagroup. So basically it won't matter if people use a mix of case on the URL or in the datagroup conents. Have been trying a few ways but seem to be hiting a bit of a brick wall. Tried using [string tolower] around the datagroup but it just converted the datagroup name to lowercase at execution time, not quite what I wanted, so the white flag is being raised :) So if anyone can help out with the last little bit it would be appreciated.
Craig - nitass
Employee
i see Aaron's irule already use string tolower, so it should work even user uses mix of case, shouldn't it?
is there anything i missed? or can you post your irule here? - nitass
Employee
[root@ve1023:Active] config b virtual bar list virtual bar { destination 172.28.19.79:80 ip protocol 6 rules myrule profiles { http {} tcp {} } } [root@ve1023:Active] config b rule myrule list rule myrule { when HTTP_REQUEST { set new_uri [class match -value -- [string tolower [HTTP::uri]] equals uri_map_dg] if {$new_uri ne ""}{ HTTP::redirect http://[HTTP::host]$new_uri } } } [root@ve1023:Active] config b class uri_map_dg list class uri_map_dg { { "/contactus" { "/public/contact-us" } "/help" { "/public/help" } } } [root@ve1023:Active] config curl -I http://172.28.19.79/contactus HTTP/1.0 302 Found Location: http://172.28.19.79/public/contact-us Server: BigIP Connection: Keep-Alive Content-Length: 0 [root@ve1023:Active] config curl -I http://172.28.19.79/contactUS HTTP/1.0 302 Found Location: http://172.28.19.79/public/contact-us Server: BigIP Connection: Keep-Alive Content-Length: 0 [root@ve1023:Active] config curl -I http://172.28.19.79/help HTTP/1.0 302 Found Location: http://172.28.19.79/public/help Server: BigIP Connection: Keep-Alive Content-Length: 0 [root@ve1023:Active] config curl -I http://172.28.19.79/Help HTTP/1.0 302 Found Location: http://172.28.19.79/public/help Server: BigIP Connection: Keep-Alive Content-Length: 0 - CraigM_17826
Altocumulus
Hi Nitass,
the case insensative match works fine on the [HTTP::path] test, but if the datagroup element name and value is enetered in uppercase then the case statement fails...or at least that is what I think I am seeing , because the lowecase PATH value will not match the uppercase values in the datagroup. Although I can document the need for the use of lowercase characters in the datagroup, if someone ignores this, then the match will fail, so I was looking at ways to overcome this. It seemed (at first glance) that this would be trivial but I can't get it to work.
I will do some more testing to make sure the issues I am seeing is actually being caused by what I think it is, it would be rather embarrasing if the cause was something else :)
Craig - hoolio
Cirrostratus
Hi Craig,
There isn't a simple way to use the class command to do a case insensitive match if the data group entries are in mixed case. You could loop through the data group entry by entry manually and set the data group key to lower case. But that's extra complexity and overhead you could avoid if you just add the entries in lower case and set the string you're looking up in the data group to lower case.
As an extra precaution, you could use a script called from cron to update any mixed case data group names to lower case via iControl or tmsh.
Aaron
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
