Forum Discussion

Brandon_High_10's avatar
Brandon_High_10
Icon for Nimbostratus rankNimbostratus
Nov 17, 2004

HTTP request rewriting

I want to use the BigIP to do something equivalent to apache's:

 

 

 

ProxyPass http://search.foo.com

 

ProxyPassReverse http://search.foo.com

 

 

 

Setting the HTTP::uri works in the HTTP_REQUEST handler. When search.foo.com sends a 302 response, the Location header needs to be rewritten and have "/search" prepended in order to work. Of course, this works in Apache, but I'd rather have my whizzy 3400s do the work.

 

 

Any suggestions?
  • gomes_127447's avatar
    gomes_127447
    Historic F5 Account
    I'm not completely familiar with ProxyPass as I'm not an Apache admin.

     

     

    But if you simply want to re-write HTTP Requests so they can be passed along to an HTTP proxy server you can do it this way:

     

     

     

    when HTTP_REQUEST {

     

     

    Rewrite the HTTP request so that a downstream proxy server will understand it

     

    HTTP::uri "http://[HTTP::host][HTTP::uri]"

     

    }

     

     

     

    Obviously you will have to tell it what proxy server to send the request to so you could at this point choose a pool, a specific pool member or node.
  • bl0ndie_127134's avatar
    bl0ndie_127134
    Historic F5 Account
    Why don't you just add a rule that does a "HTTP::header replace Location 'new value'" in the HTTP_RESPONSE event.
  • I've got it half way workign by rewriting the HTTP::uri before sending the request to the pool, but I still need to rewrite the response from the server.

     

     

    What I haven't figured out is: I only want to rewrite the responses from the pool that contains the search devices.

     

     

    For the request, the code would be:

     

     

    when HTTP_REQUEST {

     

    if { [ HTTP::uri ] starts_with "/search" } {

     

    HTTP::uri [ findstr [HTTP::uri] "/search" 7 ]

     

    pool search_pool

     

    }

     

    pool static_pool

     

    }

     

     

    and the psuedo-code for the response would be:

     

     

    when HTTP_RESPONSE {

     

    if { response comes from pool search_pool } {

     

    rewrite the Location header

     

    }

     

    }
  • One way of accomplishing this is to store the target pool in a local variable and check that on the response.

     

     

    when HTTP_REQUEST {  
       if { [ HTTP::uri ] starts_with "/search" } {  
         HTTP::uri [ findstr [HTTP::uri] "/search" 7 ]  
         pool search_pool 
         set target_pool "search_pool"  
       } 
       else { 
         pool static_pool  
         set target_pool "static_pool" 
       } 
     }

     

     

    and the psuedo-code for the response would be:

     

     

    when HTTP_RESPONSE {  
       if { $target_pool == "search_pool" } { 
          rewrite the location header 
       } 
     }

     

     

    -Joe
  • unRuleY_95363's avatar
    unRuleY_95363
    Historic F5 Account
    Instead of saving a string, I would recommend using an integer or boolean value.

    For example, instead of:

      
      set target_pool "search_pool"  
      

    use:

      
      set rewrite_reponse 1  
      

    and then in the response event simply do

      
      if { $rewrite_reponse } {  
      

    This is quite a bit faster than string comparing when you don't need to.
  • unRuleY_95363's avatar
    unRuleY_95363
    Historic F5 Account
    I would also suggest using [string range ...] instead of the findstr as you already know that the uri starts with /search.

    For example:

     
     when HTTP_REQUEST { 
        if { [HTTP::uri] starts_with "/search" } { 
           HTTP::uri [string range [HTTP::uri] 7 end] 
           pool search_pool 
           set rewrite_response 1 
        } else { 
           pool static_pool 
           set rewrite_response 0 
        } 
     } 
     

     
     when HTTP_RESPONSE { 
        if { $rewrite_response } { 
            rewrite the location header 
        } 
     } 
     

  • Excellent, it's working now. It wasn't celar to me that a variable set during a HTTP_REQUEST even would still be set during the HTTP_RESPONSE.

     

     

    I believe I encountered a bug in HTTP::uri though. With:

     

     

    if { [HTTP::uri] starts_with "/search" } {

     

    HTTP::uri [string range [HTTP::uri] 7 end]

     

     

    if the value of HTTP::uri is "/search", then it's set equal to an empty string. When the request goes to the server, it's not valid.

     

     

    So I added:

     

     

    if { [string length [HTTP::URI] == 0 ] } {

     

    HTTP::uri "/"

     

    }

     

     

    but the value of HTTP::uri remains an empty string. It seems that once it's zeroed out, it can't be set again.

     

     

    At the very least, it should still be a valid function/variable, or ideally reset to "/" when the request is sent to the server.
  • unRuleY_95363's avatar
    unRuleY_95363
    Historic F5 Account
    Try this modification to take care of your empty string problem:

     
     when HTTP_REQUEST { 
        if { [HTTP::uri] starts_with "/search" } { 
           set new_uri [string range [HTTP::uri] 7 end] 
           if { not $new_uri starts_with "/" } { 
              set new_uri "/$new_uri" 
           } 
           HTTP::uri $new_uri 
           pool search_pool 
           set rewrite_response 1 
        } else { 
           pool static_pool 
           set rewrite_response 0 
        } 
     }