Forum Discussion

Naman_65674's avatar
Naman_65674
Icon for Nimbostratus rankNimbostratus
Oct 20, 2011

Best Practice: Regex vs number of if/else

Hi,

 

 

I previously had a rule that had:

 

 

 

if {

 

$login == 1 &&

 

([string first "OP=help" [HTTP::header "location"]] == -1) &&

 

([string first "OP=token_login" [HTTP::header "location"]] == -1) &&

 

([string first "OP=error" [HTTP::header "location"]] == -1) &&

 

([string first "ERR_CODE=0x13212077 " [HTTP::header "location"]] == -1) &&

 

([string first "ERR_CODE=0x132120c8" [HTTP::header "location"]] == -1) &&

 

([string first "OP=acct_locked" [HTTP::header "location"]] == -1) } {

 

} {

 

 

..do something...

 

}

 

 

 

 

 

I then thought that this was a bit inefficient as you would have to traverse each condition before "doing something". I thought i would change this to a regex:

 

 

 

if { $login == 1 &&

 

([regexp "OP=help|OP=token_login|OP=error|ERR_CODE=0x13212077|ERR_CODE=0x132120c8|OP=acct_locked" [HTTP::header "location"]] == 0)

 

} {

 

..do something...

 

}

 

 

 

 

 

But reading some solutions on AskF5 and the iRule 101 Blogs it seems that F5 generally recommend avoiding regex for simple cases.

 

 

 

 

 

So I thought i would ask the masses....any experience or any advice on what is the best approach?

 

 

 

 

 

Thanks in advance,

 

NJ

 

 

 

  • Patrick_Chang_7's avatar
    Patrick_Chang_7
    Historic F5 Account
    We say to avoid REGEX because it can be greedy and inefficient. In this case, I would say that it should be fine if [HTTP::header "location"] is not too long a string (say 30 characters or less).
  • Actually the string can get quite long....up to 180 characters if not more....
  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    If your logic really looks like that (wanting to detect the absence of any of a number of strings in the same place), then you might also look into creating a class (data group) with your strings and using the class command, which might be even more efficient.
  • That actually might be a good idea spark, as i would be able to add the list quite easily.

     

     

    So if i had a dataclass with:

     

     

    class error_msgs {

     

    "OP=help"

     

    "OP=token_login"

     

    "OP=error"

     

    "ERR_CODE=0x13212077"

     

    "ERR_CODE=0x132120c8"

     

    "OP=acct_locked"

     

    }

     

     

    Would it be as simple as:

     

     

    if { [matchclass $::error_msgs contains [HTTP::header "location"]] == 0 } {

     

     

    ...do something...

     

    }

     

     

    I got a bit worried reading the matchclass wiki doco, especially:

     

     

    "And this example will will return the index of the first row containing any of contiguous characters in the string "green" (g, r, e, n, gr, re, ee, en, gre, ree, een, gree, reen, and green will all match):

     

     

    [matchclass "green" contains $::data_group]"

     

     

     

    I only want it to compare on the whole word.....

     

     

    -- NJ

     

     

     

     

  • Hi Naman,

    I am guessing that you are running v9.x.x if you are using "matchclass". If you are running v10.x.x you should use "class match".

    Try this:

     
    if { [matchclass [HTTP::header "Location"] contains $::error_msgs ] } {
         ....do something...
    }
    
  • (Yes i am using v9.4.8)

     

     

    Thanks for the tip. I noticed however that in the DevCentral wiki page on matchclass it said the following:

     

     

    "

     

    Note that you should not use a $:: or :: prefix on the datagroup name when using the matchclass command (or in any datagroup reference) on 9.4.4 or later. For details, see the CMP compatibility page.

     

    "

     

     

     

    So do we use instead of "$::"

     

     

     

     

    Thanks,

     

    Naman

     

  • just removing $::

    e.g.

    if {[matchclass [HTTP::header "Location"] contains error_msgs] } {
         ....do something...
    }
    
  • Hi Naman,

     

     

    To add a little bit more to what you posted about the variables. On the CMP compatibility page it says:

     

     

    Global Variables

     

    9.4.x global variables not compatible with CMP Note - demoted only if caught by validator--"global" keyword was not caught by validator (:: reference)

     

     

    Not CMP compatible:

     

    set val "$::www_redir https://${host}:${port}[HTTP::uri]\r\n$::www_opts"

     

     

    CMP compatible (v9.x):

     

    set val "[findclass "www_redir" global_vars " "] https://${host}:${port}[HTTP::uri]\r\n[findclass "www_opts" global_vars " "]"

     

     

     

    So the "$::" and "::" variable designation will still "work", but it makes the iRule CMP Non-Compliant. The impact of that would tie all traffic to the default TMM0 when processing this iRule in a CMP environment.

     

     

    Best practices are to remove it, but when you upgrade to 10.x.x, stop using the "classmatch" command all together and more to the "class match" command instead.

     

     

    Hope this helps.