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!