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