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)]