Forum Discussion
Mike_62629
Nimbostratus
Apr 07, 2008Has anyone successfully used dicts in iRules?
Has anyone successfully used dicts in iRules?
I'm currently iterating through a loop doing string comparisons and think it may be a bit more efficient to do a single dictionary lookup instead. I was having trouble getting dicts to pass the iRule Editor's syntax checking. I'm new to both iRules and TCL, so it could just be my own inexperience with the base language.
I plan to move the logic for this outside of the iRule altogether soon, but for now, here's where I am:
set myPool Application-Pool
set myExtensions {.css .gif .gif .ico .jpeg .jpg .js}
set myPath [string tolower [HTTP::path]]
pull out the extension from the path
set myIndex [string last {.} $myPath]
set myExtension [string range $myPath $myIndex end]
if the requested object's extension is in the list, serve from cache
foreach extension $myExtensions {
if { [ $extension equals $myExtension] } {
set myPool Cache-Pool
}
}
pool $myPoolI'd like to move toward something like this:
set myExtensions(.css) 1
set myExtensions(.gif) 1
set myExtensions(.ico) 1
set myExtensions(.jpeg) 1
set myExtensions(.jpg) 1
set myExtensions(.js) 1
set myPath [string tolower [HTTP::path]]
pull out the extension from the path
set myIndex [string last {.} $myPath]
set myExtension [string range $myPath $myIndex end]
if { dict exists $myExtensions $myExtension } {
pool Cache-Pool
} else {
pool Application-Pool
}- please note, this isn't the only logic used to determine cacheability, but it's the component I think could most benefit from refactoring. The list / dictionary is larger, and I'd rather do one lookup instead of 20+ string comparisons for every request. It's a fairly highly trafficked site.
10 Replies
- Nicolas_Menant
Employee
Hi,
Why not creating a string class with all the extension you want to analyze and then do the following:when HTTP_REQUEST { if {[matchclass [HTTP::path] ends_with $::Extension ] } { pool Cache-Pool } else { pool Application-Pool } }
where Extension is the name of your class
You can create a class in the Data group page. - Colin_Walker_12Historic F5 Accountnmenant is on the right track here. There's no need to do a dictionary lookup, although that's an interesting (and sneaky!) way of getting around multiple comparisons.
In this case I'd recommend a single class style match, like listed above.
Colin - Mike_62629
Nimbostratus
By Class do you guys mean a TCL class that's a subclass of string, or is this some F5/BigIP feature?
In either case, due to my inexperience with both, do you know of any resources that may be a good start for implementation? - Mike_62629
Nimbostratus
Nevermind on that, it seems pretty simple. The DevWiki had some stuff on it. - Mike_62629
Nimbostratus
class CacheableExtensions { .css .gif .ico .jpg .jpeg .js } when HTTP_REQUEST { if { [matchlass [HTTP::path] ends_with $::CacheableExtensions] } { pool Cache-Pool } else { pool Application-Pool } }
Could it be that simple? - Mike_62629
Nimbostratus
Would it be more appropriate to initialize my class within RULE_INIT so it doesnt have to be initialized and destroyed with each request? - Mike_62629
Nimbostratus
Yeap, thanks. I kept reading the matchclass wiki page and found out about data groups. What mislead me to think it was to be implemented in code was the fact that it includes a snippet of what the data group ends up looking like in the bigip.conf file. Skimming the doc made me think I had to code it somewhere.
As to dict being implemented in 8.5, thats what I thought was the problem, but couldn't find anything that would definitively state the version of TCL used in the BigIp. Thanks for the info, and to everyone who commented, thanks for the help.
For those wondering, I ended up with two classes:class CacheableExtensions { .css .js .gif *SNIP* .jpg } class CacheableDirs { /user/docs/ /user/images/ /user/videos/ } when HTTP_REQUEST { if { [matchclass [string tolower [HTTP::path]] starts_with $::CacheableDirectories] } { pool Cache-Pool } elseif { [matchclass [string tolower [HTTP::path]] ends_with $::CacheableExtensions] } { pool Cache-Pool } else { pool Application-Pool } } - Dave_Whitla_254
Nimbostratus
That's great, except sometimes you really want a dict.
Does anyone have an answer to the original question?
I'm trying to save the request headers during HTTP_REQUEST so I can conditionally log them in HTTP_RESPONSE.
My approach is to copy the headers to a dict and iterate over the dict in HTTP_RESPONSE as the request headers are no longer available by that point.
Dave - Dave_Whitla_254
Nimbostratus
Actually - this may still be current:
From http://devcentral.f5.com/Tutorials/TechTips/tabid/63/articleType/ArticleView/articleId/342/iRules-101--15--TCL-List-Handling-Commands.aspx
...
TCL: List Handling Commands
Most of the TCL commands for use in manipulating lists are available in iRules:
list - Create a list
split - Split a string into a proper Tcl list
join - Create a string by joining together list elements
concat - Join lists together
llength - Count the number of elements in a list
lindex - Retrieve an element from a list
lrange - Return one or more adjacent elements from a list
linsert - Insert elements into a list
lreplace - Replace elements in a list with new elements
lsort - Sort the elements of a list
lsearch - See if a list contains a particular element
The remaining documented list handling commands, lrepeat, lreverse, & dict, are not available within iRules. We’ll cover the commands from above that get the most traffic here on the forums.
... - hoolio
Cirrostratus
Hi Dave,
You could try saving the value of [HTTP::request] split on a \r in HTTP_REQUEST and then use TCL list commands to parse this in the response. I think this should be more efficient than looping through all of the request headers and saving them to a list. You'll also get the full request line from HTTP::request, which can't be retrieved whole in one command otherwise.
Can you try something like this:when HTTP_REQUEST { Save the request headers split on a carriage return set request_headers [split [HTTP::request] \\\r] } when HTTP_RESPONSE { log local0. "request header count: [llength $request_headers]" Loop through the request headers for {set i 0} {$i < [llength $request_headers]} {incr i} { Trim off the leading \r\n from each list element and log it log local0. "$i: [string trimleft [lindex $request_headers $i]]" } }
Aaron
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
