Forum Discussion
Martin_Kaiser_1
Nimbostratus
Oct 20, 2005using getfield to split up URIs
Hi there,
can anyone of you show me the correct syntax for using the function getfield in an iRule?
What I want to do is split up an URI like "/webstart/portal/customer_id/some/more/fields" and extract the field customer_id, that is always in the third position. The value should be stored in a variable that can be used again later for dynamically choosing pools or redirects in case of LB_FAILED.
Thanks in advance!
Regards,
Martin
14 Replies
- Martin,
Here is the documentation for getfield (from the BIG-IP Users Manual)getfield
The getfield command splits a string on a character, and returns the string corresponding to the specific field.
The syntax of the getfield command is:
getfield
So, for your example, you'll want to use the HTTP::uri for the "string" value, a slash for the "split" value and value of 4 for the "field" (the first field will be empty since there is nothing before the split char).when HTTP_REQUEST { set cust_id [getfield [HTTP::uri] "/" 4]] if { $cust_id equals "company1" } { pool company1_pool } elseif { $cust_id equals "company2" } { pool company2_pool } }
If your uri's can be mixed case, you might want to throw in a "string tolower" in there to convert the HTTP::uri to lowercase before the comparison.when HTTP_REQUEST { set cust_id [string tolower [getfield [HTTP::uri] "/" 4]]] if { $cust_id equals "company1" } { pool company1_pool } elseif { $cust_id equals "company2" } { pool company2_pool } }
Good luck!
-Joe - Martin_Kaiser_1
Nimbostratus
Joe,
thanks for the quick and competent reply!
I'm just beginning to realize the oppurtunities iRules provide and am quite overwhelmed!
See you,
Martin - Martin_Kaiser_1
Nimbostratus
As I am beginning to realize the opportunities, would it also be possible to do something like that:when HTTP_REQUEST { set cust_id [getfield [HTTP::uri] "/" 4]] pool $cust_id_pool }
I suppose not? - You suppose wrong, well almost...
Everything can be a variable so you can dynamically create a pool name based on inbound variables and then use the pool command (or with any other command)
Your rule doesn't work as-is but it would with a slight tweak. "$cust_id_pool" would be evaluated as the variable which doesn't exist. What you'll want to do is enclose the variable "cust_id" in braces like this:when HTTP_REQUEST { set cust_id [getfield [HTTP::uri] "/" 4]] pool ${cust_id}_pool }
There are examples in the forums where customers are mapping portions of the hostnames and sections of the uri's into pool names, using portions of the hostnames to redirect to another uri on a common hostname for use in vanity domains,etc. You are really only limited by your imagination in what you can do.
I've been trying to highlight iRules that kind of stand out in my blog. You might want to take a peek when you get a chance:http://devcentral.f5.com/weblogs/joe/category/28.aspxClick here
Also, if you aren't already, click the "subscribe" checkbox at the top of each forum to get email notifications on each post. It's a good way to get some good ideas as well.
Oh, and hop on over to the TCL reference at Sourceforge for any language specific issues (such as regular expressions, binary scanning, string manipulation, etc):http://tmml.sourceforge.net/doc/tcl/Click here
Good Luck!
-Joe - Martin_Kaiser_1
Nimbostratus
Hi again,
The rule I have built so far seem to work properly, thank you!
Now I need to extract a customer ID from a field within the URI that is not always in the same place. I need to search for the string "view=cust_id" that is somewhere in the path and use the second half of it as variable. Any hint how to achieve this?
Regards, Martin - Martin_Kaiser_1
Nimbostratus
I just found the answer for myself:when LB_FAILED { set uri [HTTP::uri] if {$uri contains "&view="} { set regexp_result [regexp {view=([a-zA-Z]+)} $uri viewstring cust_id] HTTP::redirect https://some.maintenancesite.com/$cust_id } }
Thanks nevertheless!
Martin
PS: Is there any way to avoid using the variables $regexp_result and $viewstring in the above example? Those will never get used... - You can get rid of the regexp_result variable by removing the brackets around the regexp call
when LB_FAILED { set uri [HTTP::uri] if {$uri contains "&view="} { regexp {view=([a-zA-Z]+)} $uri viewstring cust_id HTTP::redirect https://some.maintenancesite.com/$cust_id } }
If you want to get rid of the viewstring variable as well, you could do something like the following:when LB_FAILED { set uri [HTTP::uri] if {$uri contains "&view="} { set cust_id [lindex [regexp -inline {view=([a-zA-Z]+)} $uri] 1] HTTP::redirect https://some.maintenancesite.com/$cust_id } }
The "-inline" argument to regexp tells it to return a list instead of putting the results in the match args. The lindex command will extract a specified element from a list. In this case the second one (or index 1). The info on these commands are available in the TCL Reference at Sourceforge
http://tmml.sourceforge.net/doc/tcl/
Click here
The only comment I have is whether cust_id alwasy is only characters from a-z. If you want to include underscores, numbers, etc, then you can replace the a-z ranges with a word character expressionwhen LB_FAILED { set uri [HTTP::uri] if {$uri contains "&view="} { regexp {view=(\w+)} $uri viewstring cust_id HTTP::redirect https://some.maintenancesite.com/$cust_id } }
Honestly, I'm not sure which one is more efficient. Putting the values into two variables, or a 2 element temporary list and a single variable. Probably the first option is better performance wise, but I'm not sure.
One more approach you could take to this is to avoid the "contains" match and rely on the regexp return code.when LB_FAILED { set retcode [regexp {view=([a-zA-Z]+)} [HTTP::uri] viewstring cust_id] if { 1 == $retcode } { HTTP::redirect https://some.maintenancesite.com/$cust_id } }
or, to make it even more concice you could do the following:when LB_FAILED { if { 1 == [regexp {view=([a-zA-Z]+)} [HTTP::uri] viewstring cust_id] } { HTTP::redirect https://some.maintenancesite.com/$cust_id } }
Try them all out and see which works better for you...
-Joe - Martin_Kaiser_1
Nimbostratus
joe,
I Think I will go with the first suggestion. I suppose, this one should be the most efficient as it has the least assignments of variables. Anyway, I don't think that any of them will show significant performance differences for the end users.
Unfortunately, the "contains" statement cannot be avoided, since I have to include some more elseif-branches for some other URIs...
Thanks for your help!
Martin - unRuleY_95363Historic F5 AccountWe also have some URI convenience functions like URI::query. So you can simply write a rule like this:
when LB_FAILED { set cust_id [URI::query [HTTP::uri] "view"] if {$cust_id ne ""} { HTTP::redirect https://some.maintenancesite.com/$cust_id } } - unRuleY_95363Historic F5 AccountBTW, Joe's last example is actually best as it completely avoids using any variables. This will actually yield the best performance, but if you are not concerned about that then I would go with the readability of using some variables.
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
