Forum Discussion

BaltoStar_12467's avatar
Aug 17, 2013

irule class match each query param separately

Data Group dg1
param1=p11&param2=p21 := host1
param1=p12&param2=p22 := host2

The problem is that some request urls might list their query params in reverse order

param2=p21&param1=p11

Therefore I need to match query params individually.

So I have two problems to solve :

  1. extract from

    [HTTP::query]
    the param segments for
    param1
    and
    param2

  2. determine if both

    param1_segment
    and
    param2_segment
    are found together in some key in
    dg1

So something like :

set param1 "param1"
set param2 "param2"
set param1_segment = [[HTTP:query] $param1]
set param2_segment = [[HTTP:query] $param2]
if { (class match $param1_segment&$param2_segment equals dg1) or (class match $param2_segment&$param1_segment equals dg1) } {

NOTE: I know the above is wrong in terms of both language elements and syntax. I'm just providing to better describe the problem I need to solve.

Because my use-case might extend to 3 query params ( in any order ) it might be better to AND together class match for each query param segment.

  • I think it would almost make more sense to just reorder the params, and then look them up in the data group. So something like this:

    when HTTP_REQUEST {
       if { [URI::query [HTTP::uri]] ne "" } {
          set param1 [URI::query "?[URI::query [HTTP::uri]]" param1]
          set param2 [URI::query "?[URI::query [HTTP::uri]]" param2]
          set param3 [URI::query "?[URI::query [HTTP::uri]]" param3]
    
          set paramstring "param1=$param1&param2=$param2&param3=$param3"
    
          if { [class match $paramstring equals dg1] } {
             ... do something here ...
          }
       }
    }
    

    You'll of course need some additional error checking in there, to make sure params exist, but you get the idea.

  • Aaron_Forster_3's avatar
    Aaron_Forster_3
    Historic F5 Account

    Your use case might extend to three parameters as in if it extends it will always have three or as in a request may have two or may have three?

    If you want to pull out individual parameters and re-order them you can extract with URI::query. Unlike HTTP::query it doesn't pull from the existing request, you have to feed it a URI to extract the query from. It has two forms. The first simply extracts the query portion like HTTP::query (but could be used on a source other than the current request) and the second extracts a specific parameter. you would call it like this:

    [URI::query [HTTP::uri] param1]

    which would return "param1" from the above request.

    You could use this to quickly re-order the values of the parameters.

    set param1 "param1"
    set param2 "param2"
    set param1_segment = [URI::query [HTTP::uri] $param1]
    set param2_segment = [URI::query [HTTP::uri] $param2]
    

    Now the class command has a number of different ways you can call it. equals really only tells you that what you are looking for matches one of the entries in it. you can also add the -value flag to get the value of that option. I.E.

    class match -value $param1_segment&$param2_segment equals dg1 wouldn't return true for "param1=p11&param2=p21" it would return host1.

    The upshot is you just construct a single lookup. put param1 and 2 together, if 3 exists add that one.

    last bit is to avoid having to stuff all those various possible combinations together you simply stuff them together in the correct order. assign the results to what ever you're going to use it for (variable, pool selection, etc) and to avoid errors/have a fallback if it doesn't exist wrap the whole thing in a TCL catch statement

    if { [catch {pool class match -value $param1_segment&$param2_segment equals dg1}] {
        pool fallBackPool
    }
    

    The contents of the if statement will be executed only if the first pool assignment fails. which it would if there was no pool returned from the class match value.

    EDIT: My first attempt to post a response failed so I had to retype it and forgot to add links URI::query https://devcentral.f5.com/wiki/iRules.URI__query.ashx

    class https://devcentral.f5.com/wiki/iRules.class.ashx

    catch http://www.tcl.tk/man/tcl8.5/TclCmd/catch.htm