For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

ShinRyuX's avatar
ShinRyuX
Icon for Nimbostratus rankNimbostratus
Mar 29, 2016

Any way to shorten this switch case iRule?

Here is my iRule.

when HTTP_REQUEST {
    switch -glob [string tolower [HTTP::path]] {
        "/dir1" -
        "/dir1/" {
            HTTP::respond 301 Location "http://www.domain1.com"
        }
        "/dir1/dir2" -
        "/dir1/dir2/" {
            HTTP::respond 301 Location "http://www.domain2.com"
        }
    }
}

I thought of putting "dir1*" but it would interfere with my 2nd condition.

16 Replies

  • Hello,

    The switch condition are taken in the order, so you can define a /dir1* but after /dir1/dir2* for example.

    when HTTP_REQUEST {
        switch -glob [string tolower [HTTP::path]] {
            "/dir1/dir2*" {
                HTTP::respond 301 Location "http://www.domain2.com"
            }
            "/dir1*" {
                HTTP::respond 301 Location "http://www.domain1.com"
            }
        }
    }
    
    • ShinRyuX's avatar
      ShinRyuX
      Icon for Nimbostratus rankNimbostratus
      Hello, That solution would work but this iRule is actually a simplified version of my current iRule where I have over 100 redirect links along with uri parameters extracted from original URL. I would have to re-order the conditions in ways to prevent any conflicts from occuring. Is there anything that can be done without re-arraging the order? I tried few things like putting "dir1?" or even "dir1[ ?]" but they dont satisfy both conditinos i want. Thank You
    • Yann_Desmarest_'s avatar
      Yann_Desmarest_
      Icon for Nacreous rankNacreous
      What is the logic behind your redirect links ? Maybe, you can extract patterns from your request uri and change the Location value accordingly with a string map command
    • ShinRyuX's avatar
      ShinRyuX
      Icon for Nimbostratus rankNimbostratus
      This is the full logic when HTTP_REQUEST { Extract URL parameters set urlPath "[string tolower [HTTP::path]]?" if {[string tolower [HTTP::uri]] contains "?"} { set newUri [string map -nocase [list $urlPath "?"] [HTTP::uri]] } else { set newUri "" } Redirection Logic case switch -glob [string tolower [HTTP::path]] { "/file1.html" { HTTP::respond 301 Location "http://www.newdomain.com/en-US/destination1$newUri" } "/dir1" - "/dir1/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination2$newUri" } "/dir1/dir2" - "/dir1/dir2/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination3$newUri" } "/dir1/dir2/dir3" - "/dir1/dir2/dir3/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination4$newUri" } ... } The list goes on but the logic remains the same.
  • Hello,

    The switch condition are taken in the order, so you can define a /dir1* but after /dir1/dir2* for example.

    when HTTP_REQUEST {
        switch -glob [string tolower [HTTP::path]] {
            "/dir1/dir2*" {
                HTTP::respond 301 Location "http://www.domain2.com"
            }
            "/dir1*" {
                HTTP::respond 301 Location "http://www.domain1.com"
            }
        }
    }
    
    • ShinRyuX's avatar
      ShinRyuX
      Icon for Nimbostratus rankNimbostratus
      Hello, That solution would work but this iRule is actually a simplified version of my current iRule where I have over 100 redirect links along with uri parameters extracted from original URL. I would have to re-order the conditions in ways to prevent any conflicts from occuring. Is there anything that can be done without re-arraging the order? I tried few things like putting "dir1?" or even "dir1[ ?]" but they dont satisfy both conditinos i want. Thank You
    • Yann_Desmarest's avatar
      Yann_Desmarest
      Icon for Cirrus rankCirrus
      What is the logic behind your redirect links ? Maybe, you can extract patterns from your request uri and change the Location value accordingly with a string map command
    • ShinRyuX's avatar
      ShinRyuX
      Icon for Nimbostratus rankNimbostratus
      This is the full logic when HTTP_REQUEST { Extract URL parameters set urlPath "[string tolower [HTTP::path]]?" if {[string tolower [HTTP::uri]] contains "?"} { set newUri [string map -nocase [list $urlPath "?"] [HTTP::uri]] } else { set newUri "" } Redirection Logic case switch -glob [string tolower [HTTP::path]] { "/file1.html" { HTTP::respond 301 Location "http://www.newdomain.com/en-US/destination1$newUri" } "/dir1" - "/dir1/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination2$newUri" } "/dir1/dir2" - "/dir1/dir2/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination3$newUri" } "/dir1/dir2/dir3" - "/dir1/dir2/dir3/" { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination4$newUri" } ... } The list goes on but the logic remains the same.
  • Use -glob flag if you have wildcards or other expressions. With your current iRule, the -glob flag is not mandatory.

     

    You may also want to have a look at LTM Local Traffic policy feature. I'd use a Local Traffic Policy over iRules these days whenever possible.

     

    When it comes to shortening the iRule, Yann got the same solution posted a bit before me (removed mine)

     

  • Arie's avatar
    Arie
    Icon for Altostratus rankAltostratus

    As far as I know Local Traffic Policies still don't allow control over the redirect type (301, 302, etc.). That being the case a policy may not be the best solution since often a 301 would be preferable.

     

    It's disappointing that F5 is still not conforming to the RFCs on this. Hoping to see that soon!

     

  • My comment on top didnt come out right. Here is the full Logic of my iRule.

    when HTTP_REQUEST {
         Extract URL parameters
        set urlPath "[string tolower [HTTP::path]]?"
        if {[string tolower [HTTP::uri]] contains "?"} {
            set newUri [string map -nocase [list $urlPath "?"] [HTTP::uri]]
        }
        else {
            set newUri ""
        }
    
         Redirection Logic case
        switch -glob [string tolower [HTTP::path]] {
            "/file1.html" {
                HTTP::respond 301 Location "http://www.newdomain.com/en-US/destination1$newUri"
            }
            "/dir1" -
            "/dir1/" {
                HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination2$newUri"
            }
            "/dir1/dir2" -
            "/dir1/dir2/" {
                HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination3$newUri"
            }
            "/dir1/dir2/dir3" -
            "/dir1/dir2/dir3/" {
                HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/destination4$newUri"
            }
                    ...
    }
    

    The list goes on but the logic remains the same.

    • Yann_Desmarest's avatar
      Yann_Desmarest
      Icon for Cirrus rankCirrus
      Maybe you can define a data-group of type string. The string is dirX and the value is destinationX. Then you apply a trimleft on the HTTP::path to get the last part of the uri, then check the presence of that uri part within the data-group using a command similar to if { [class match $trimuri equals "uripart_dg" ] } { HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/[class lookup $trimuri uripart_dg]$newUri" } and finally apply th
  • Maybe you can define a data-group of type string. The string is dirX and the value is destinationX. Then you apply a trimleft on the HTTP::path to get the last part of the uri, then check the presence of that uri part within the data-group using a command similar to :

    if { [class match $trimuri equals "uripart_dg" ] } {
        HTTP::respond 301 Location "http://www.newdomain.com/fr-FR/[class lookup $trimuri uripart_dg]$newUri"
    }
    
  • I believe that the data group answer is the best one if you are in fact not performing globbing. Here is how I would do it (though not tested!):

    tmsh create ltm data-group internal redirector-base type string { records add { \
        "/file1.html" { data "http://www.newdomain.com/en-US/destination1" } \
        "/dir1" { data "http://www.newdomain.com/en-US/destination2" } \
        "/dir1/" { data "http://www.newdomain.com/en-US/destination2" } \
        ... etc ...
        } }
    

    (You could -- and probably should -- do this with an imported external data-group, but I use an internal group for illustration).

    Then the rule:

    when HTTP_REQUEST {
        set base [class lookup "[HTTP::path]" redirector-base]
        
        if { $base ne "" } {
             Extract URL parameters
            set urlPath "[string tolower [HTTP::path]]?"
            if {[string tolower [HTTP::uri]] contains "?"} {
                set newUri [string map -nocase [list $urlPath "?"] [HTTP::uri]]
            }
            else {
                set newUri ""
            }
    
            HTTP::respond 301 Location "$base$newURI" 
        }
    }
    

    Note a few things:

    1. This will not work if you need to employ globbing (though, strictly speaking, you could iterate through a list of glob matchers that are keys in a data-group, but that may be [considerably] less efficient than the switch);
    2. I moved the
      $newURI
      computation inside of the conditional. If there is no match, there's no point in performing the calculation;
    3. You use a pattern that I very commonly see, namely:
      [string tolower [HTTP::path]]
      . While it is true that some filesystems are case-insensitive, RFC 2616 states that everything but the scheme (i.e., the leading 'http' in this case) and the hostname should be treated in a case-sensitive manner. See RFC 2616 3.2.3 [1]. As a practical matter, "flattening" the case of the path costs CPU cycles and I believe it to be of no practical value, especially if users are not typically typing in the uri-path part, but rather they are getting to these locations via hyperlinks.

    [1] Specifically:

       When comparing two URIs to decide if they match or not, a client
       SHOULD use a case-sensitive octet-by-octet comparison of the entire
       URIs, with these exceptions:
          - A port that is empty or not given is equivalent to the default
            port for that URI-reference;
          - Comparisons of host names MUST be case-insensitive;
          - Comparisons of scheme names MUST be case-insensitive;
          - An empty abs_path is equivalent to an abs_path of "/".