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

tatmotiv's avatar
tatmotiv
Icon for Cirrostratus rankCirrostratus
Feb 26, 2016

pool-member specific rewrite of http URI

Hi everybody,

I have the following requirement:

There is a pool consisting of two members (same IP, different port). HTTP requests coming in to the according virtual must be rewritten as follows: If the URI starts with "/abc/" and selected pool member is 1, the first part of the URI needs to rewritten to "/def/", if member 2 is selected by the LB, it needs to be rewritten to "/ghi/". Due to the member-specific part of this, a rewrite or stream profile cannot be used without an iRule.

I tried the following iRule, which seemed to work at first (using cURL as testing tool):

 

when LB_SELECTED {
  if { [HTTP::uri] starts_with "/abc/" } {
    if { [LB::server port] equals 8001 } {
      HTTP::uri [string map {"/abc/" "/def/"} [HTTP::uri] ]
    }
    elseif { [LB::server port] equals 8002 } {
      HTTP::uri [string map {"/abc/" "/ghi/"} [HTTP::uri] ]
    }
  }
}

 

However, it turned out that subsequent http requests coming in through the same http 1.1 session with keep-alive are not rewritten, which is totally understandable, because LB_SELECTED is only triggered once.

Hence, after struggling with variable substituition with string maps in curly braces for a while, I moved forward to the following rule:

 

when LB_SELECTED {
  if { [LB::server port] equals 8001 } {
    set newuri_prefix "/def/"
  }
  elseif { [LB::server port] equals 8002 } {
    set newuri_prefix "/ghi/"
  }
}

when HTTP_REQUEST {
  if { [HTTP::uri] starts_with "/abc/" } {
    HTTP::uri [string map -nocase [list "/abc/" "$newuri_prefix"] [HTTP::uri] ] 
  }
}

 

This does not work either, because HTTP_REQUEST obviously is triggered before LB_SELECTED, meaning that $newuri_prefix is empty. I came to this conclusion because of the following log entries being written when the rule is executed:

 

err tmm[10833]: 01220001:3: TCL error: ...somerulename...  - can't read "newuri_prefix": no such variable     while executing "list "/abc/" "$newuri_prefix""

 

Because of that, I also cannot replace "LB_SELECTED" with "HTTP_REQUEST" in the first rule above, because [LB::server port] is not yet set then.

Now I'm running out of ideas... Any suggestions on how to achieve this? Any hint is appreciated. Many thanks in advance!

1 Reply

  • Hi Tatmotiv,

    you may try to use the HTTP_REQUEST_SEND event. This event will trigger after LB_SELECTED has choosen the member and also on every subsequent HTTP request...

     

    when HTTP_REQUEST_SEND {
        clientside {
            if { [HTTP::uri] starts_with "/abc/" } {
                if { [LB::server port] equals 8001 } {
                    HTTP::uri "/def[string range [HTTP::uri] 4 end]"
                } 
                elseif { [LB::server port] equals 8002 } {
                    HTTP::uri "/ghi[string range [HTTP::uri] 4 end]"
                }
            }
        }
    }
    

     

    Note: I've changed your code to use [string range] command in combination with substitution. Its much more stable and also performant to just cut/add the leading portion that needs to become replaced. You may have to change the 4 to the length of the string that needs to become cutted.

    Cheers, Kai