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

eirikn's avatar
eirikn
Icon for Nimbostratus rankNimbostratus
Jan 06, 2016

iRule Array with string map redirects not working

Hi,

I'm trying to create a iRule with arrays that sendt traffic to both pools and 302 redirection.

The iRule should behave like this:

The first array simply forwards traffic to a pool. It's working as intended.

The second array should redirects certain URI's to a different URL. It get's difficult when I also need to append some of the the URI to the redirect target.

Example:

Requests to https://bee.test.example.no/cfs/whatever should redirect to https://cfs-ws-customer.vendor.no/whatever

So I would like to remove "/cfs/" from the URI but append/keep the rest and add it to the redirect URL.

I've tried using string map, but I can's seem to get it to work.

More examples:

Requets to bee.test.example.no/caf/whatever/example should redirect to https://banktest.portal.no/dummy-text_to_show-something-web/whatever/example

Requets to bank.test.example.no/insurance/whatever/dummy should redirect to http://test.dummy.customer.no/example/whatever/dummy.

Requets to redaktor-*.test.example.no/cfs/example/stuff should redirect to https://cfs-ws-customer.vendor.no/example/stuff

I would appreciate any help or tips! Let me know if something is unclear 🙂

 

`when HTTP_REQUEST {
 array set pools {               
    sliders.test.example.no                         pool_example_test
    bee.test.example.no                             pool_example_test
    tinypower.test.example.no                       pool_example_test
    tbank.test.example.no                           pool_example_test
    bank.test.example.no                            pool_example_test
    womvalley.test.example.no                       pool_example_test
    redakto-                                        pool_example_redaktor
    priceapi1-sitecore1.test.example.no             pool_example_redaktor

 }     
    array set redirects {               

    /caf            https://banktest.portal.no/dummy-text_to_show-something-web/

    /insurance      http://test.dummy.customer.no/example/

    /cfs            https://cfs-ws-customer.vendor.no/

 }    

       foreach {web_uri new_destination} [array get redirects] {

           if { [string tolower [HTTP::uri]] starts_with "$web_uri" } {
                    HTTP::respond 302 noserver Location "$new_destination[string map {$web_uri [HTTP::uri]} [HTTP::uri]]"
                    return
      }

    }
       foreach {host_header member_pool} [array get pools] {

           if { ([string tolower [HTTP::host]] equals $host_header) }{
                    pool $member_pool
                    return
      }
            elseif { ([string tolower [HTTP::host]] starts_with $host_header) }{
                    pool $member_pool
                    return
    }


 }

 HTTP::respond 200 Content "This site does not exist"

 

}`

3 Replies

  • Hello, I think you are combining curly braces with variables and this avoids their expansion. So, it should be something like this:

    HTTP::respond 302 noserver Location "$new_destination[string map "$web_uri [HTTP::uri]" [HTTP::uri]]"

    However, I think that the result will not be what you expect with those combinations, then, as a first shot, you could do like this:

    HTTP::respond 302 noserver Location "$new_destination[string range [HTTP::uri] [expr [string len $web_uri]+1] end]"

    Anyway, why do you not do that by using "data group" and "class match" to avoid iteration in their arrays? Maybe it could be more easy to do.

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

    Another point,is the second part that seems to have the same effect when the operator "equals" and "starts_with", will have the same final execution, then it seems to me to be redundant and unnecessary to use the first operator "equals". Sorry if I did not analyze as a whole.

    I think that's all, I hope I have helped you!

    Regards.

  • Hi Eirikn,

    I've to second Cjuniors opinion to use [class] instead of [array] for this specific task. The reason for this is, that an [array] can't be easily crawled in a $STRING starts_with [array names] fashion. Well, using a [foreach] loop will work, but its far away from being ideal... 😉

    But if you still want to stick with this approach, then you may want to take a look to the iRule below.

    It resolves your question be using a [string map -nocase [list $web_uri ""] [HTTP::uri]] and has some additional performance optimizations included (e.g. using RULE_INIT to define the [array]'s not on every request, removed the trailing / slashes from redirect locations, changed the code to use [array names], removed the duplicated execution of [string tolower [HTTP::host]] and finally combined the [if $host_header] statements.

    BTW: I duno if a starts_with operator for every $host_header would be sufficient, too?

     

    when RULE_INIT {
        unset -nocomplain static::pools
        array set static::pools {
                sliders.test.example.no                     pool_example_test
                bee.test.example.no                         pool_example_test
                tinypower.test.example.no                   pool_example_test
                tbank.test.example.no                       pool_example_test
                bank.test.example.no                        pool_example_test
                womvalley.test.example.no                   pool_example_test
                redakto-                                    pool_example_redaktor
                priceapi1-sitecore1.test.example.no         pool_example_redaktor
        }
        unset -nocomplain static::redirects
        array set static::redirects {
            /caf            https://banktest.portal.no/dummy-text_to_show-something-web
            /insurance      http://test.dummy.customer.no/example
            /cfs            https://cfs-ws-customer.vendor.no
        }
    }
    
    when HTTP_REQUEST {
        foreach web_uri [array names static::redirects] {
            if { [string tolower [HTTP::uri]] starts_with "$web_uri" } then {
                HTTP::respond 302 noserver Location "$static::redirects($web_uri)[string map -nocase [list $web_uri ""] [HTTP::uri]]"
                return
            }
        }
        foreach host_header [array names static::pools] {
            set low_host [string tolower [HTTP::host]]
            if { ($low_host equals $host_header) or 
                 ($low_host starts_with $host_header) } then {
                pool $static::pools($host_header)
                return
            }
        }
        HTTP::respond 200 Content "This site does not exist"
    }
    

     

    Cheers, Kai

  • eirikn's avatar
    eirikn
    Icon for Nimbostratus rankNimbostratus

    Hey guys,

     

    Sorry for the late reply.

     

    I got it working with your help, but eventually we changed the code so we did not need to stringmap rewrite.

     

    Thanks for great input anyway!