iRule: modify uri and response

 

I'm trying to find a way with an iRule (or any functionality really) to take a url like https://apple.fruit.com/application/xyz.html and convert it to https://peanut.bean.com/application/xyz.html as it goes through the bigip (running v9) then pass it to the servers on the Bea Weblogic backend (doing all SSL encrypt/decrypt on the LB, backend just gets plain http). The catch is we cannot redirect the browser client to the peanut.bean.com site, the end user must always see apple.fruit.com. To make it even more complicated, sometimes the app will send back a payload with a URL inside it for the user that we need to change from peanut.bean.com to apple.fruit.com.

This one is a follow up to my last example: iRule: modifying the uri without a redirect except that the response content now needs to be modified as well to map to the client's known uri. This can be done with some fun regexp's returning indices for the matches.

when HTTP_REQUEST {
  # Don't allow data to be chunked so we can correctly
  # replace payload below
  if { [HTTP::version] eq "1.1" } {
      if { [HTTP::header is_keepalive] } {
         HTTP::header replace "Connection" "Keep-Alive"
      }
      HTTP::version "1.0"
  }

  # change host header
  if { [HTTP::host] eq "apple.fruit.com" } {
    HTTP::header replace "Host" "peanut.bean.com"
    set ::patch_apple_and_banana 1
  }
}

when HTTP_RESPONSE {
  if { $::patch_apple_and_banana } {  
    # collect response data
    if { [HTTP::header exists "Content-Length"] } {
       set content_length [HTTP::header "Content-Length"]
    } else {
       set content_length 4294967295
    }
    if { $content_length > 0 } {
       HTTP::collect $content_length
    }
  }
}

when HTTP_RESPONSE_DATA {
  if { $::patch_apple_and_banana } {
    set find "peanut.bean.com"
    set replace "apple.fruit.com"
    set offset 0
    set diff [expr [string length $replace] - [string length $find]]

    # Get indices of all instances of find string in the payload
    set indices [regexp -all -inline -indices $find [HTTP::payload]]  
    foreach idx $indices {
      set start [expr [lindex $idx 0] + $offset]
      set end [expr [lindex $idx 1] + $offset]
      set len [expr {$end - $start + 1}]

      # replace the instance of find with the contents of replace
      HTTP::payload replace $start $len $replace

      # modify offset if the replace string is larger or smaller
      # than find.
      incr offset $diff
    }
  }
}

unRuleY quickly pointed out that you might want to hard code some of those expr's if you the find and replace are known. Extra string length's are costly when run 1000's of times. Hard coding the "diff" value could save some cycles. Also replacing $find and $replace with the actual values will reduce the memory overhead of those local variables.

-Joe

 

[Listening to: The Sacred and Profane - Smashing Pumpkins - MACHINA/The Machines of God (04:22)]
Published Jul 27, 2005
Version 1.0

Was this article helpful?

3 Comments

  • If you have individual questions about the commands and what this code does, post them up on the forums and we'll try to answer them.

     

     

    We are currently working on a new documentation project for iRules that should be out very soon. That may help as well.

     

     

    Also, feel free to contact Consulting, I'm sure they would be able to help you out.

     

     

    -Joe
  • What updates are you referring to? The features to rewrite the URI and user agent can be done as described in the blog post. The User-Agent can be modified with the "HTTP::header replace" command.

     

     

    If you can be more specific about what issues you need to be addressed, we'll see if we can help.

     

     

    -Joe
  • Hello, I have been used the irule in 12.1.3.6 version and its working fine, but when I upgrade to 12.1.3.7 this message appear:

     

    01220001:3: TCL error: /Common/iRule_superwas - Illegal argument (line 9) invoked from within "HTTP::collect $content_length"

     

    Please helpme